#include "liveMediaRead.h"
#include "commonDefine.h"
#include "rtsp_live_stream.h"
#include "imageGraphics.h"



#include "ot_common_vpss.h"
#include "ss_mpi_vpss.h"
#include "ss_mpi_vo.h"
#include "ot_common_vo.h"


#include "xop/RtspServer.h"
#include "net/Timer.h"

#include <thread>
#include <atomic>
#include <memory>
#include <iostream>
#include <string>
#include <mutex>

#include <unistd.h>

//#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <pthread.h>

std::atomic_bool flagRunOSD(false);
std::thread handle_vis_draw_osd;

bool enableOSD = false;
std::atomic_bool flagRunRtsp(false);
std::thread handle_rtsp;

void thr_vis_detect_draw(int vpssGrp,int vpssChn,int vencChn);




td_s32 vpss_chn_set_depth(int vpssGrp, int vpssChn, int depth)
{
    ot_vpss_chn_attr vpss_chn_attr = {};
    td_s32 s32Ret = ss_mpi_vpss_get_chn_attr(vpssGrp, vpssChn, &vpss_chn_attr);
    if (s32Ret != TD_SUCCESS)
    {
        ERRO_PRT("error vpss grp %d chn %d,ss_mpi_vpss_get_chn_attr %x\n", vpssGrp, vpssChn, s32Ret);
        return s32Ret;
    }

    vpss_chn_attr.depth = depth;
    s32Ret = ss_mpi_vpss_set_chn_attr(vpssGrp, vpssChn, &vpss_chn_attr);
    if (s32Ret != TD_SUCCESS)
    {
        ERRO_PRT("error vpss grp %d chn %d,ss_mpi_vpss_set_chn_attr %x\n", vpssGrp, vpssChn, s32Ret);
        return s32Ret;
    }

    return 0;
}

int rtsp_venc_init_h264(int vpssGrp,int vpssChn,int vencChn,bool osdEnable){
    sample_comm_venc_chn_param venc_chn_param = {};
    venc_chn_param.size = PIC_1080P;
    venc_chn_param.gop = VIS_FRAME_RATE;
    venc_chn_param.frame_rate = VIS_FRAME_RATE;
    venc_chn_param.is_rcn_ref_share_buf = TD_FALSE;
    venc_chn_param.type =  OT_PT_H264;
    sample_comm_sys_get_pic_size(PIC_1080P,&venc_chn_param.venc_size);

    td_s32 s32Ret = sample_comm_venc_start(vencChn, &venc_chn_param);
    if (s32Ret != TD_SUCCESS)
    {
        ERRO_PRT("error sample_comm_venc_start %x\n", s32Ret);
        return s32Ret;
    }


    //如果启用osd则不绑定vpss与venc
    if (osdEnable == false)
    {
        sample_comm_vpss_bind_venc(vpssGrp,vpssChn,vencChn);
    }else{

        s32Ret = vpss_chn_set_depth(vpssGrp,vpssChn,1); 
        if(s32Ret != TD_SUCCESS){
            return s32Ret;
        }

        flagRunOSD = true;
        handle_vis_draw_osd = std::thread(thr_vis_detect_draw,vpssGrp,vpssChn,vencChn);
    }

    enableOSD = osdEnable;

    return 0;
}


int rtsp_venc_destory_h264(int vpssGrp,int vpssChn,int vencChn){
    if(enableOSD){
        sample_comm_vpss_un_bind_venc(vpssGrp,vpssChn,vencChn);
    }else{
        flagRunOSD = false;
        handle_vis_draw_osd.join();
    }
    
    sample_comm_venc_stop(vencChn);

    INFO_PRT("rtsp venc is destory\n");
    return 0;
}



image_detect_info  rect_newest;
std::mutex mutex_osd;
void recognized_target_update(image_detect_info& rect){
    std::lock_guard<std::mutex> lock(mutex_osd);
    rect_newest = rect;
}

void thr_vis_detect_draw(int vpssGrp,int vpssChn,int vencChn){
    
    
    pthread_setname_np(handle_vis_draw_osd.native_handle(),"detect_draw");

    while (flagRunOSD)
    {
        ot_video_frame_info vpss_chn_frame = {};
        td_s32 s32Ret = ss_mpi_vpss_get_chn_frame(vpssGrp, vpssChn, &vpss_chn_frame, 2000);
        if (s32Ret != TD_SUCCESS)
        {
            ERRO_PRT("error ss_mpi_vpss_get_chn_frame %x\n", s32Ret);
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            continue;
        }

        image_detect_info draw_rect;
        {
            std::lock_guard<std::mutex> lock(mutex_osd);
            draw_rect = rect_newest;
        }

        // 绘制目标框
        vgsDrawRectangle(&vpss_chn_frame,draw_rect);

        s32Ret = ss_mpi_venc_send_frame(vencChn,&vpss_chn_frame,2000);
        if(s32Ret != TD_SUCCESS){
            ERRO_PRT("error ss_mpi_venc_send_frame %x\n",s32Ret);
        }

        // 发送图像至SDI路
        s32Ret = ss_mpi_vo_send_frame(VCAP_VO_DEV_UHD,VCAP_VO_CHN_ID,&vpss_chn_frame,2000);
        if(s32Ret != TD_SUCCESS){
            ERRO_PRT("error ss_mpi_vo_send_frame %x\n",s32Ret);
        }

        // 发送图像至CVBS路
        s32Ret = ss_mpi_vo_send_frame(VCAP_VO_DEV_CVBS,VCAP_VO_CHN_CVBS,&vpss_chn_frame,2000);
        if(s32Ret != TD_SUCCESS){
            ERRO_PRT("error ss_mpi_vo_send_frame %x\n",s32Ret);
        }

        s32Ret = ss_mpi_vpss_release_chn_frame(vpssGrp,vpssChn,&vpss_chn_frame);
        if(s32Ret != TD_SUCCESS){
            ERRO_PRT("error ss_mpi_vpss_release_chn_frame %x\n",s32Ret);
        }
    }
    INFO_PRT("vpss -> venc osd draw thread is quit\n");
}



void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, h264LiveStream* h264Stream)
{       
	int buf_size = 2000000;
	std::unique_ptr<uint8_t> frame_buf(new uint8_t[buf_size]);

	while(flagRunRtsp) {
		
        uint32_t pts;
        int frame_size = h264Stream->readFrame((char*)frame_buf.get(), buf_size,&pts);
		if(frame_size > 0) {
			xop::AVFrame videoFrame = {0};
			videoFrame.type = 0; 
			videoFrame.size = frame_size;
			videoFrame.timestamp = xop::H264Source::GetTimestamp();
			videoFrame.buffer.reset(new uint8_t[videoFrame.size]);    
			memcpy(videoFrame.buffer.get(), frame_buf.get(), videoFrame.size);
			rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame);
		}
		else {
			ERRO_PRT("error read frame.sleep 3s\n");
			std::this_thread::sleep_for(std::chrono::seconds(3));
		}
	}

    INFO_PRT("rtsp send thread is quit\n");
}



int rtsp_server_run()
{	

    h264LiveStream h264Stream(0);

	std::string suffix = "live";
	std::string ip = "192.168.1.10";
	std::string port = "554";
	std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;
	
	std::shared_ptr<xop::EventLoop> event_loop(new xop::EventLoop());
	std::shared_ptr<xop::RtspServer> server = xop::RtspServer::Create(event_loop.get());

	if (!server->Start("0.0.0.0", atoi(port.c_str()))) {
		INFO_PRT("RTSP Server listen on %s failed.\n", port.c_str());
		return 0;
	}

#ifdef AUTH_CONFIG
	server->SetAuthConfig("-_-", "admin", "12345");
#endif

	xop::MediaSession *session = xop::MediaSession::CreateNew("live"); 
	session->AddSource(xop::channel_0, xop::H264Source::CreateNew(VIS_FRAME_RATE)); 
	//session->StartMulticast(); 
	session->AddNotifyConnectedCallback([&] (xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port){
		printf("RTSP client connect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);
		h264Stream.reqIDRFrame();
	});
   
	session->AddNotifyDisconnectedCallback([](xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port) {
		printf("RTSP client disconnect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);
	});

	xop::MediaSessionId session_id = server->AddSession(session);
    
    flagRunRtsp = true;
	handle_rtsp = std::thread(SendFrameThread, server.get(), session_id, &h264Stream);
	

	std::cout << "Play URL: " << rtsp_url << std::endl;

	while (flagRunRtsp) {
		xop::Timer::Sleep(5);
	}

    INFO_PRT("rtsp server is quit\n");
	return 0;
}

int rtsp_server_quit(void){
    flagRunRtsp = false;
    handle_rtsp.join();
    return 0;
}


